/*
 * perceptron.h
 *
 *  Created on: Feb 28, 2011
 *      Author: tqlong
 */

#ifndef PERCEPTRON_H_
#define PERCEPTRON_H_

#include "dataset.h"
#include <armadillo>

class OnlineLearningAlgorithm {
public:
  double predict_;

  virtual void setParameters(const std::vector<double>& params) = 0;
  virtual double update(const arma::vec& x, double y, double p) = 0;
  virtual double predict(const arma::vec& x) = 0;
  virtual void print() const = 0;
};

class LearningAlgorithm : public OnlineLearningAlgorithm {
public:
  void setParameters(const std::vector<double>& params) = 0;
  double update(const arma::vec& x, double y, double p) { return 0; }
  virtual double update(Dataset& data) = 0;
  virtual double predict(const arma::vec& x) = 0;
  void print() const = 0;
};

class Perceptron : public OnlineLearningAlgorithm
{
public:
  arma::vec w_;
  double alpha_; // learning rate

  Perceptron(int d = 1) : w_(arma::randn(d)), alpha_(1.0) {}
  void setParameters(const std::vector<double>& params);
  double update(const arma::vec& x, double y, double p);
  double predict(const arma::vec& x);
  void print() const { std::cout << w_; }
};

class WeightedMajority : public OnlineLearningAlgorithm
{
public:
  std::vector<OnlineLearningAlgorithm*> expert_;
  std::vector<double> pred_;
  std::vector<double> weight_;
  double beta_;

  WeightedMajority() : beta_(0.5) {}

  // implement virtual members
  void setParameters(const std::vector<double>& params);
  double update(const arma::vec& x, double y, double p);
  double predict(const arma::vec& x);
  void print() const;

  // other members
  void add(OnlineLearningAlgorithm& algo);
  int n_expert() const { return expert_.size(); }
};

class L1LossL2Reg : public LearningAlgorithm
{
public:
  arma::vec w_;
  double alpha_; // learning rate
  double C_; // regularized parameter
  int maxiter_;
  arma::vec a_;
  arma::vec Qii_, Dii_;
  double U_;

  L1LossL2Reg(int d = 1) : w_(arma::randn(d)), alpha_(1.0), C_(100.0), maxiter_(100) {}
  void setParameters(const std::vector<double>& params);
  double update(Dataset& data);
  double predict(const arma::vec& x);
  void iterate(Dataset& data);
  virtual void prepareQD(Dataset& data);
  void print() const { std::cout << w_; }
};

class L2LossL2Reg : public L1LossL2Reg
{
public:
  L2LossL2Reg(int d = 1) : L1LossL2Reg(d) {}
  void prepareQD(Dataset& data);
};

class Compare
{
public:
  double tol_;
  Compare(double tol = 1e-10) : tol_(tol) {}
  bool equal(double x, double y) { return fabs(x - y) < tol_; }
  bool less(double x, double y) { return x < y-tol_; }
  bool greater(double x, double y) { return x > y+tol_; }
  bool lesseq(double x, double y) { return x <= y + tol_; }
  bool greatereq(double x, double y) { return x >= y-tol_; }
};

#endif /* PERCEPTRON_H_ */
